<?php

require_once ("Common/InputValidationHandler.php");
require_once("Common/LogHandler.php");

class UserHandler {
	private $DBConnection = null;
	private $userTabelName = "user";
	private $userClass = "User";

	public function __construct(DBConnection $DBConnection, $DBPrefix) {
		$this -> DBConnection = $DBConnection;
		$this -> userTabelName = $DBPrefix . $this -> userTabelName;
	}

	/**
	 * Create Table!
	 * Public function to create the table User with given Prifix (test_ or live_)
	 * public members/fields
	 * userId PK auto increment
	 * UserName Unique, Varchar 15, not null
	 * PassWord varchar 250, not null
	 * Email varchar 250, not null
	 * Salt varchar 250, not null
	 *
	 * Index on PK (userId) and UserName
	 */
	public function createTable() {
		$sql = "CREATE TABLE IF NOT EXISTS `" . $this -> userTabelName . "` (
			  `userId` int(11) NOT NULL AUTO_INCREMENT,
			  `UserName` varchar(15) NOT NULL,
			  `PassWord` varchar(250) NOT NULL,
			  `Email` varchar(250) NOT NULL,
			  `Salt` varchar(250) NOT NULL,
			  `IsAdmin` tinyint(1) NOT NULL,
			  PRIMARY KEY (`userId`),
			  UNIQUE KEY `UserName_2` (`UserName`),
			  KEY `UserName` (`UserName`)
			) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=50 ;";

		return $this -> DBConnection -> RunQuery($sql);
	}

	/**
	 * Public function to remove UserTable from DB
	 * @access Public
	 * @param -
	 * @return bool
	 */
	public function removeTable() {
		return $this -> DBConnection -> dropTable($this -> userTabelName);
	}

	/**
	 * A function called to create a new random pass for user
	 * and to insert into DB.
	 * Will return user object with the new pass
	 * @access public
	 * @param User
	 * @Return User
	 */
	public function updatePasswordOnUser(User $user, $newPass = false) {
		if ($newPass === false) {
			$user -> PassWord = $this -> generateRandomPassword();
		} else {
			$user -> PassWord = $newPass;
		}

		if (!$this -> isValidUser($user)) {
			return false;
		}

		if (!$this -> updateUser($user)) {
			return false;
		}

		$user = $this -> getUserByuserId($user -> userId);

		return $user;
	}

	/**
	 * Function to generate a random password
	 * The letter l (lowercase L) and the number 1
	 * have been removed, as they can be mistaken
	 * for each other.
	 * @access Private
	 * @param -
	 * @return string new random password
	 */
	private function generateRandomPassword() {

		$chars = "abcdefghijkmnopqrstuvwxyz023456789";
		srand((double)microtime() * 1000000);
		$pass = '';

		$i = 0;
		while ($i <= 7) {
			$num = rand() % 33;
			$tmp = substr($chars, $num, 1);
			$pass = $pass . $tmp;
			$i++;
		}
		return $pass;
	}

	/**
	 * Funtion to get all user from UserTable
	 * @access public
	 * @param -
	 * @return Array with User Object
	 */
	public function getAllUsers() {
		$sql = "SELECT * FROM $this->userTabelName";

		$stmt = $this -> DBConnection -> Prepare($sql);

		return $this -> fetchObjects($stmt, "userId");
	}

	/**
	 * Function to get a user from userTable with given userId
	 * @access public
	 * @param int UserId
	 * @return User object
	 */
	public function getUserByuserId($userId) {
		$sql = "SELECT * FROM $this->userTabelName WHERE userId = ?";
		
		$stmt = $this -> DBConnection -> Prepare($sql);

		$stmt -> bind_param("i", $userId);

		$array = $this -> fetchObjects($stmt, "userId");

		if (count($array) === 1) {
			return $array[$userId];
		} else {
			return false;
		}
	}

	/**
	 * Function to get a user from userTable with given UserName
	 * @access public
	 * @param string username
	 * @return UserObject
	 */
	public function getUserByUserName($userName) {
		$sql = "SELECT * FROM $this->userTabelName WHERE UserName = ?";
		
		LogHandler::logMessage("TestLog in GetUserByUserName: " . $userName);
		
		$stmt = $this -> DBConnection -> Prepare($sql);
		
		if($stmt === false){
			return null;
		}

		$stmt -> bind_param("s", $userName);

		$array = $this -> fetchObjects($stmt, "UserName");

		if (count($array) === 1) {
			//Make sure the index is the same casing as the entered user
			if (array_key_exists($userName, $array)) {
				return $array[$userName];
			}
			return NULL;
		} else {
			return NULL;
		}
	}

	/**
	 * Function to insert a new user into userTable
	 * @access public
	 * @param User object
	 * @return Bool or  if true, User object
	 */
	public function insertUser(User $user) {
		//Make sure the user is OK before inserting
		if (!$this -> isValidUser($user)) {
			return false;
		}

		$sql = "INSERT INTO $this->userTabelName (UserName, PassWord, Email, Salt, IsAdmin) VALUES(?,?,?,?,?)";
		$stmt = $this -> DBConnection -> Prepare($sql);
		$stmt -> bind_param("ssssi", $user -> UserName, $user -> PassWord, $user -> Email, $user -> Salt, $user -> IsAdmin);

		if ($stmt === FALSE) {
			return false;
		}

		if ($stmt -> execute() === false) {
			return false;
		}

		$user -> userId = $stmt -> insert_id;
		$stmt -> close();
		return $user;
	}

	/**
	 * Function to remove a user from UserTable in DB
	 * @access Public
	 * @param User object
	 * @return Bool
	 */
	public function deleteUser(User $user) {
		$sql = "DELETE FROM $this->userTabelName WHERE userId = ?";

		$stmt = $this -> DBConnection -> prepare($sql);
		$stmt -> bind_param("i", $user -> userId);

		if ($stmt === false) {
			return false;
		}

		$stmt -> execute();
		$stmt -> close();

		return true;
	}

	/**
	 * Function to update a user in usertable
	 * @access public
	 * @param User
	 * @return Bool
	 */
	public function updateUser(User $user) {
		//Make sure the user is OK before inserting
		if (!$this -> isValidUser($user)) {
			return false;
		}

		$sql = "UPDATE $this->userTabelName SET userId=?, UserName=?, PassWord=?, Email=?, Salt=?, IsAdmin=? WHERE userId=?";

		$stmt = $this -> DBConnection -> prepare($sql);
		$stmt -> bind_param("issssii", $user -> userId, $user -> UserName, $user -> PassWord, $user -> Email, $user -> Salt, $user -> IsAdmin, $user -> userId);

		if ($stmt === FALSE) {
			return false;
		}

		if ($stmt -> execute() === false) {
			return false;
		}

		$stmt -> close();
		return true;
	}

	/**
	 * Function to get all run a query and get objects from DB
	 * @access public
	 * @param SQLStatement, Indexer = witch tabel name to index array by
	 * @return array with UserObjects
	 */
	public function fetchObjects($stmt, $indexer) {
		$retArray = array();
		if($stmt->execute() === false){
			return $retArray;
        }
		
		$stmt->bind_result($userId, $UserName, $PassWord, $Email, $Salt, $IsAdmin);
		
		while($stmt->fetch()){
			$user = User::create($userId, $UserName, $PassWord, $Email, $Salt, $IsAdmin);
			$retArray[$user->$indexer] = $user;
		}
		
		$stmt->close();
		return $retArray;
	}

	/**
	 * Function to validate a user befor insert or update
	 * @access private
	 * @param User
	 * @return bool
	 */
	private function isValidUser(User $user) {
		//Make sure the user is OK before inserting
		if (InputValidationHandler::isValidUser($user -> UserName) === false or InputValidationHandler::isValidPass($user -> PassWord) === false or InputValidationHandler::isValidEmail($user -> Email) === false) {
			return false;
		}
		return true;
	}

}
